package com.hangxintong.common.base.service;

import com.hangxintong.common.base.Filter;
import com.hangxintong.common.base.entity.BaseJpaModel;
import com.hangxintong.common.base.entity.BaseJpaRepository;
import com.hangxintong.common.base.entity.IEntity;
import lombok.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class BaseJpaService<T extends BaseJpaModel>  {

    private final static Logger logger = LoggerFactory.getLogger(BaseJpaService.class);

    @Autowired
    protected Validator validator;

    /**
     * 驼峰命名转为下划线命名
     * @param para
     * @return
     */
    public static String camelToUnderline(String para) {
        StringBuilder sb = new StringBuilder(para);
        int temp = 0;//定位
        if (!para.contains("_")) {
            for (int i = 0; i < para.length(); i++) {
                if (Character.isUpperCase(para.charAt(i))) {
                    sb.insert(i + temp, "_");
                    temp += 1;
                }
            }
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 属性复制
     *
     * @param source
     * @param clazz
     * @return
     */
    public static <T> T copyProperties(Object source, @NonNull Class<T> clazz) {
        if (source == null) {
            return null;
        }
        T target = BeanUtils.instantiateClass(clazz);
        BeanUtils.copyProperties(source, target);
        return target;
    }


    /**
     * 属性复制（略部分属性）
     *
     *
     * @param source
     * @param clazz
     * @param ignoreProperties
     * @return
     */
    public static <T> T copyPropertiesIgnore(Object source, @NotNull Class<T> clazz, String... ignoreProperties) {
        if (source == null) {
            return null;
        }
        T target = BeanUtils.instantiateClass(clazz);
        BeanUtils.copyProperties(source, target, ignoreProperties);
        return target;
    }


    /**
     * 复制部分属性
     *
     *
     * @param source
     * @param clazz
     * @param specificProperties
     * @return
     */
    public static <T> T copyPropertiesSpecific(Object source, Class<T> clazz, String... specificProperties) {
        if (source == null) {
            return null;
        }
        T target = BeanUtils.instantiateClass(clazz);
        if (specificProperties == null) {
            return target;
        }
        String[] specificList = specificProperties;
        final BeanWrapper src = new BeanWrapperImpl(source);
        final BeanWrapper trg = new BeanWrapperImpl(target);
        for (final String propertyName : specificList) {
            trg.setPropertyValue(propertyName,
                    src.getPropertyValue(propertyName));
        }
        return target;
    }

    /**
     * 拷贝属性到另外一个对象，忽略JPA的核心属性
     * <B>
     * 注意：不支持同名但不同数据类型的属性，对于JPA维护的对象也不支持集合的列表。
     * 同时会忽略 id、 createdAt、 updatedAt、 version 这几个基础属性。
     * </B>
     *
     * @param source
     * @param target
     * @return
     */
    public static void copyPropertiesIgnoreJPAKeys(Object source, Object target) {
        BeanUtils.copyProperties(source, target, "id", "createdAt", "updatedAt", "version");
    }


    /**
     * 拷贝属性到另外一个对象
     *
     * @param source
     * @param target
     * @return
     */
    public static void copyPropertiesToObject(Object source, Object target) {
        BeanUtils.copyProperties(source, target);
    }

    /**
     * 生成长度为32的随机串
     */
    public static String randomNonce32() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 把 vo 的属性 拷贝到 实体 并保存。
     * 如果 vo 的 id > 0， 则会从数据库装载实体；
     * 否则创建一个新实体。
     *
     * @param vo
     * @return
     */
    public T findAndCopyProperties(IEntity vo) {
        T rst;
        try {
            if (vo.getId() != null && vo.getId() > 0) {
                rst = getRepository().getOne(vo.getId());
            } else {

                //  获取子类类型：
                Class clz = this.getClass(); //this指的是当前运行的实例（子类实例）
                // 获取类的泛型父类
                Type type = clz.getGenericSuperclass();
                //  把Type转换为具体的类型: BaseAction<Standard>
                ParameterizedType pt = (ParameterizedType) type;//将泛型父类转换为具体的那种类型
                Class modelClass = (Class) pt.getActualTypeArguments()[0];//获取具体泛型类Action中的泛型
                // 创建泛型类的的对象
                rst = (T) modelClass.getConstructor().newInstance();
            }
            copyPropertiesIgnoreJPAKeys(vo, rst);
            return rst;
        } catch (Exception ex) {
            throw new RuntimeException("动态创建拷贝对象实例时出错", ex);
        }
    }

    /**
     * 把 T 的列表 转换成 K 的列表
     *
     * @param sourceList
     * @param convertMethod
     * @param <T>
     * @param <K>
     * @return
     */
    public static <T, K> List<K> toCnvList(@NonNull List<T> sourceList, @NonNull Function<T, K> convertMethod) {
        return sourceList.stream().map(convertMethod).collect(Collectors.toList());
    }

    /**
     * 把 T 的分页 转换成 K 的分页
     * @param sourcePage
     * @param convertMethod
     * @param <T>
     * @param <K>
     * @return
     */
    public static <T, K> Page<K> toCnvPage(@NonNull Page<T> sourcePage, @NonNull Function<T, K> convertMethod) {
        List<T> listT = sourcePage.getContent();
        List<K> listK;
        if (listT != null && listT.size() > 0) {
            listK = toCnvList(listT, convertMethod);
        } else {
            listK = new ArrayList<>();
        }
        return new PageImpl<>(listK, sourcePage.getPageable(), sourcePage.getTotalElements());
    }

    /**
     * 数据仓库
     * 根据具体内容通过 Spring 注入仓库后， 通过本方法返回
     *
     * @return
     */
    protected abstract BaseJpaRepository<T> getRepository();

    /**
     * 更新前检查
     * 保证参数传入没有问题。以及没有修改的部分不做处理。
     * 只提供了默认实现 —— Hibernate Validate 并转化为 IllegalArgumentException。
     * 各子类根据具体情况 Override， 比如从数据库读取当前值， 然后选择合适的属性拷贝。
     *
     * @param object
     * @return
     */
    protected T checkUp4Update(T object) throws IllegalArgumentException {
        Set<ConstraintViolation<T>> violationSet = validator.validate(object);
        if (!CollectionUtils.isEmpty(violationSet)) {
            throw violationSetToException(violationSet);
        }
        return object;
    }

    /**
     * 把约束转成业务异常
     *
     * @param violationSet
     * @return
     */
    protected IllegalArgumentException violationSetToException(@NotNull Set<ConstraintViolation<T>> violationSet) {
        StringBuilder sb = new StringBuilder();
        violationSet.forEach(cv -> sb.append(cv.getMessage()).append("；"));
        return new IllegalArgumentException(sb.toString());
    }

    /**
     * 创建 或者 更新
     * 请根据具体情况 Override {@link #checkUp4Update(BaseJpaModel<BaseJpaModel>)}
     *
     * @param object
     * @return
     */
    public T save(T object) {
        T toUpdate = checkUp4Update(object);
        return getRepository().save(toUpdate);
    }

    /**
     * 保存 或者 更新 对象列表
     * 注意：方法不会经过 {@link #checkUp4Update(BaseJpaModel<BaseJpaModel>)} 进行更行前检查
     *
     * @param list
     */
    public void save(Collection<T> list) {
        list.forEach(this::save);
    }

    /**
     * 删除
     *
     * @param id
     */
    public void delete(Long id) {

        getRepository().deleteById(id);
    }

    /**
     * 删除
     *
     * @param object
     */
    public void delete(T object) {
        getRepository().delete(object);
    }

    /**
     * 总记录数
     *
     * @return
     */
    public long countAll() {
        return getRepository().count();
    }

    /**
     * 查询一条记录
     *
     * @param id
     * @return
     */
    public T find(Long id) {
        return getRepository().findById(id).orElse(null);
    }

    /**
     * 综合分页查询
     *
     * @param filters
     * @param pageable
     * @return
     */
    public Page<T> findPage(List<Filter> filters, Pageable pageable) {
        return getRepository().findAll(getSpecification(filters), pageable);
    }

    /**
     * 查找全部
     *
     * @param filters
     * @return
     */
    public List<T> findAll(List<Filter> filters) {
        return getRepository().findAll(getSpecification(filters));
    }

    /**
     * 把自定义的查询条件列表翻译成Spring的Specification
     *
     * @param filters
     * @return
     */
    protected final Specification<T> getSpecification(List<Filter> filters) {
        if (filters == null || filters.size() == 0) {
            return null;
        }
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery,
                                         CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                filters.stream().forEach(f -> predicates.addAll(getPredicate(f, root, criteriaBuilder)));
                return andTogether(predicates, criteriaBuilder);
            }
        };
    }

    /**
     * And 连接多个查询条件
     *
     * @param predicates
     * @param cb
     * @return
     */
    private final Predicate andTogether(List<Predicate> predicates, CriteriaBuilder cb) {
        return cb.and(predicates.toArray(new Predicate[0]));
    }

    /**
     * 把自定义的查询条件对象翻译成Spring的CriteriaBuilder
     *
     * @param filter
     * @param root
     * @param builder
     * @return
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    private final List<Predicate> getPredicate(Filter filter, Root<T> root, CriteriaBuilder builder) {
        List<Predicate> resultList = new ArrayList<>();
        String[] propertyNameArray = filter.getName().split("\\.");
        String propertyName = null;

        Join join = null;
        for (int i = 0; i < propertyNameArray.length; i++) {
            if (i == propertyNameArray.length - 1) {
                propertyName = propertyNameArray[i];
            } else {
                if (join == null) {
                    join = root.join(propertyNameArray[i]);
                } else {
                    join = join.join(propertyNameArray[i]);
                }
            }
        }
        if ("string".equalsIgnoreCase(filter.getType())) {
            if (join == null) {
                if ("or".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.or(builder.like(root.get(propertyName), filter.getValue())));
                } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.like(root.get(propertyName), filter.getValue()));
                } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.notLike(root.get(propertyName), filter.getValue()));
                }
            } else {
                if ("or".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.or(builder.like(join.get(propertyName), filter.getValue())));
                } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.like(join.get(propertyName), filter.getValue()));
                } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.notLike(join.get(propertyName), filter.getValue()));
                }
            }
        } else if ("number".equalsIgnoreCase(filter.getType())) {
            if (filter.getMin() != null) {
                Double d = Double.parseDouble(filter.getMin());
                if (join == null) {
                    resultList.add(builder.greaterThanOrEqualTo(root.get(propertyName), d));
                } else {
                    resultList.add(builder.greaterThanOrEqualTo(join.get(propertyName), d));
                }
            }
            if (filter.getMax() != null) {
                Double d = Double.parseDouble(filter.getMax());
                if (join == null) {
                    resultList.add(builder.lessThanOrEqualTo(root.get(propertyName), d));
                } else {
                    resultList.add(builder.lessThanOrEqualTo(join.get(propertyName), d));
                }
            }
            if (filter.getValue() != null && filter.getMin() == null && filter.getMax() == null) {
                Double d = Double.parseDouble(filter.getValue());
                if (join == null) {
                    if ("or".equalsIgnoreCase(filter.getCondition())) {
                        resultList.add(builder.or(builder.equal(root.get(propertyName), d)));
                    } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                        resultList.add(builder.equal(root.get(propertyName), d));
                    } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                        resultList.add(builder.notEqual(root.get(propertyName), d));
                    }
                } else {
                    if ("or".equalsIgnoreCase(filter.getCondition())) {
                        resultList.add(builder.or(builder.equal(join.get(propertyName), d)));
                    } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                        resultList.add(builder.equal(join.get(propertyName), d));
                    } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                        resultList.add(builder.notEqual(join.get(propertyName), d));
                    }
                }
            }
        } else if ("date".equalsIgnoreCase(filter.getType())) {
            if (filter.getMin() != null) {
                Date date = str2Date(filter.getMin());
                if (date != null) {
                    if (join == null) {
                        resultList.add(builder.greaterThanOrEqualTo(root.get(propertyName), date));
                    } else {
                        resultList.add(builder.greaterThanOrEqualTo(join.get(propertyName), date));
                    }
                }
            }
            if (filter.getMax() != null) {
                Date date = str2Date(filter.getMax());
                if (date != null) {
                    if (join == null) {
                        resultList.add(builder.lessThanOrEqualTo(root.get(propertyName), date));
                    } else {
                        resultList.add(builder.lessThanOrEqualTo(join.get(propertyName), date));
                    }
                }
            }
            if (filter.getValue() != null && filter.getMin() == null && filter.getMax() == null) {
                Date date = str2Date(filter.getValue());
                if (date != null) {
                    if (join == null) {
                        if ("or".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.or(builder.notEqual(root.get(propertyName), date)));
                        } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.equal(root.get(propertyName), date));
                        } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.notEqual(root.get(propertyName), date));
                        }
                    } else {
                        if ("or".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.or(builder.notEqual(join.get(propertyName), date)));
                        } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.equal(join.get(propertyName), date));
                        } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.notEqual(join.get(propertyName), date));
                        }
                    }
                }
            }
        } else if ("enum".equalsIgnoreCase(filter.getType())) {
            if (filter.getEnumName() != null) {
                try {
                    Class enumType = Class.forName(filter.getEnumName());
                    Enum enumObj = Enum.valueOf(enumType, filter.getValue());
                    if (join == null) {
                        if ("or".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.or(builder.equal(root.get(propertyName), enumObj)));
                        } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.equal(root.get(propertyName), enumObj));
                        } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.notEqual(root.get(propertyName), enumObj));
                        }
                    } else {
                        if ("or".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.or(builder.equal(join.get(propertyName), enumObj)));
                        } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.equal(join.get(propertyName), enumObj));
                        } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                            resultList.add(builder.notEqual(join.get(propertyName), enumObj));
                        }
                    }
                } catch (Exception ex) {
                    //  类型异常应该在开发阶段才会发生
                    logger.warn(ex.getMessage(), ex);
                }
            }
        } else if ("null".equalsIgnoreCase(filter.getType())) {
            if (join == null) {
                if ("or".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.or(builder.isNull(root.get(propertyName))));
                } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.isNull(root.get(propertyName)));
                } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.isNotNull(root.get(propertyName)));
                }
            } else {
                if ("or".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.or(builder.isNull(join.get(propertyName))));
                } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.isNull(join.get(propertyName)));
                } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                    resultList.add(builder.isNotNull(join.get(propertyName)));
                }
            }
        } else if ("boolean".equalsIgnoreCase(filter.getType())) {
            boolean isTrue = "true".equalsIgnoreCase(filter.getCondition()) ||
                    "1".equals(filter.getCondition());
            if (join == null) {
                if ("or".equalsIgnoreCase(filter.getCondition())) {
                    if (isTrue) {
                        resultList.add(builder.or(builder.isTrue(root.get(propertyName))));
                    } else {
                        resultList.add(builder.or(builder.isFalse(root.get(propertyName))));
                    }
                } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                    if (isTrue) {
                        resultList.add(builder.isTrue(root.get(propertyName)));
                    } else {
                        resultList.add(builder.isFalse(root.get(propertyName)));
                    }
                } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                    if (isTrue) {
                        resultList.add(builder.isFalse(root.get(propertyName)));
                    } else {
                        resultList.add(builder.isTrue(root.get(propertyName)));
                    }
                }
            } else {
                if ("or".equalsIgnoreCase(filter.getCondition())) {
                    if (isTrue) {
                        resultList.add(builder.or(builder.isTrue(join.get(propertyName))));
                    } else {
                        resultList.add(builder.or(builder.isFalse(join.get(propertyName))));
                    }
                } else if ("equal".equalsIgnoreCase(filter.getCondition())) {
                    if (isTrue) {
                        resultList.add(builder.isTrue(join.get(propertyName)));
                    } else {
                        resultList.add(builder.isFalse(join.get(propertyName)));
                    }
                } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                    if (isTrue) {
                        resultList.add(builder.isFalse(join.get(propertyName)));
                    } else {
                        resultList.add(builder.isTrue(join.get(propertyName)));
                    }
                }
            }
        } else if ("list".equalsIgnoreCase(filter.getType())) {
            if (filter.getObjectList() != null && filter.getObjectList().size() > 0) {
                CriteriaBuilder.In<Object> in = builder.in(root.get(propertyName));
                for (Object id : filter.getObjectList()) {
                    in.value(id);
                }
                if (join == null) {
                    resultList.add(in);
                } else {
                    resultList.add(in);
                }
            }
        }
        return resultList;
    }

    /**
     * 把 s 转换成日期
     *
     * @param s
     * @return
     */
    private Date str2Date(String s) {
        try {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            return df.parse(s);
        } catch (ParseException e) {
            logger.warn(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 给字符串的前后增加 %， 已满足模糊查询的格式
     *
     * @param s
     * @return
     */
    protected String toLikeString(String s) {
        StringBuilder sb = new StringBuilder();
        if (s == null) {
            return null;
        }
        if (!s.startsWith("%")) {
            sb.append("%");
        }
        sb.append(s);
        if (!s.endsWith("%")) {
            sb.append("%");
        }
        return sb.toString();
    }

    /**
     * 把过滤参数转换成 MyBatis 需要的 Where SQL 段
     *
     * @param filters 注意： filter 的 type 不支持 enum， 但额外多支持了 select。 不支持 or 逻辑！
     * @return
     */
    protected List<String> getFilterParamsList4MyBatis(List<Filter> filters) {
        List<String> params = new ArrayList<>();
        if (filters != null && filters.size() > 0) {
            for (Filter filter : filters) {
                if ("string".equalsIgnoreCase(filter.getType())) {
                    if ("equal".equalsIgnoreCase(filter.getCondition())) {
                        params.add(filter.getName() + " like '%" + escapeSql(filter.getValue()) + "%'");
                    } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                        params.add(filter.getName() + " not like '%" + escapeSql(filter.getValue()) + "%'");
                    }
                } else if ("select".equalsIgnoreCase(filter.getType())) {
                    params.add(filter.getName() + " = '" + escapeSql(filter.getValue()) + "'");
                } else if ("null".equalsIgnoreCase(filter.getType())) {
                    if ("equal".equalsIgnoreCase(filter.getCondition())) {
                        params.add(filter.getName() + " is null ");
                    } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                        params.add(filter.getName() + " is not null ");
                    }
                } else if ("number".equalsIgnoreCase(filter.getType())) {
                    StringBuffer sb = new StringBuffer();
                    if (!StringUtils.isEmpty(filter.getMin())) {
                        try {
                            sb.append(filter.getName() + ">=" + Double.parseDouble(filter.getMin()));
                        } catch (NumberFormatException nfe) {
                            //  转换失败就忽略这参数
                            logger.warn(nfe.getMessage(), nfe);
                        }
                    }
                    if (!StringUtils.isEmpty(filter.getMax())) {
                        if (sb.length() > 0) {
                            sb.append(" AND ");
                        }
                        try {
                            sb.append(filter.getName() + "<=" + Double.parseDouble(filter.getMax()));
                        } catch (NumberFormatException nfe) {
                            //  转换失败就忽略这参数
                            logger.warn(nfe.getMessage(), nfe);
                        }
                    }
                    if (sb.length() == 0 && !StringUtils.isEmpty(filter.getValue())) {
                        try {
                            if ("equal".equalsIgnoreCase(filter.getCondition())) {
                                sb.append(filter.getName() + "=" + Double.parseDouble(filter.getValue()));
                            } else if ("not".equalsIgnoreCase(filter.getCondition())) {
                                sb.append(filter.getName() + "<>" + Double.parseDouble(filter.getValue()));
                            }
                        } catch (NumberFormatException nfe) {
                            //  转换失败就忽略这参数
                            logger.warn(nfe.getMessage(), nfe);
                        }
                    }
                    if (sb.length() > 0) {
                        sb.insert(0, "(");
                        sb.append(")");
                    }
                    if (sb.length() > 0) {
                        params.add(sb.toString());
                    } else {
                        logger.warn(filter.getName() + "过滤条件被忽略了。");
                    }
                } else if ("date".equalsIgnoreCase(filter.getType())) {
                    StringBuffer sb = new StringBuffer();
                    if (!StringUtils.isEmpty(filter.getMin())) {
                        sb.append(filter.getName() + ">=" + str2MySQLDate(filter.getMin()));
                    }
                    if (!StringUtils.isEmpty(filter.getMax())) {
                        if (sb.length() > 0) {
                            sb.append(" AND ");
                        }
                        sb.append(filter.getName() + "<=" + str2MySQLDate(filter.getMax()));
                    }
                    if (sb.length() == 0 && !StringUtils.isEmpty(filter.getValue())) {
                        sb.append(filter.getName() + "=" + str2MySQLDate(filter.getValue()));
                    }
                    if (sb.length() > 0) {
                        sb.insert(0, "(");
                        sb.append(")");
                    }
                    if (sb.length() > 0) {
                        params.add(sb.toString());
                    } else {
                        logger.warn(filter.getName() + "过滤条件被忽略了。");
                    }
                } else if ("comparestring".equalsIgnoreCase(filter.getType())) {
                    StringBuffer sb = new StringBuffer();
                    if (!StringUtils.isEmpty(filter.getMin())) {
                        sb.append(filter.getName() + ">= '" + filter.getMin() + "'");
                    }
                    if (!StringUtils.isEmpty(filter.getMax())) {
                        if (sb.length() > 0) {
                            sb.append(" AND ");
                        }
                        sb.append(filter.getName() + "<= '" + filter.getMax() + "'");
                    }
                    if (sb.length() == 0 && !StringUtils.isEmpty(filter.getValue())) {
                        sb.append(filter.getName() + "= '" + filter.getValue() + "'");
                    }
                    if (sb.length() > 0) {
                        sb.insert(0, "(");
                        sb.append(")");
                    }
                    if (sb.length() > 0) {
                        params.add(sb.toString());
                    } else {
                        logger.warn(filter.getName() + "过滤条件被忽略了。");
                    }
                }
            }
        }
        return params;
    }

    /**
     * 排序参数转SQL片段
     *
     * @param pageable
     * @return
     */
    protected String getOrderClause4MyBatis(Pageable pageable) {
        StringBuilder sb = new StringBuilder();
        if (pageable != null && pageable.getSort() != null) {
            pageable.getSort().forEach(o -> {
                String ts = camelToUnderline(o.getProperty());
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(ts);
                if (o.isDescending()) {
                    sb.append(" desc");
                }
            });
        }
        return sb.toString();
    }

    /**
     * 替换掉 SQL 中的保留字符
     *
     * @param source
     * @return
     */
    protected String escapeSql(String source) {
        if (source == null) {
            return null;
        }
        return StringUtils.replace(source, "'", "''");
    }

    /**
     * 把 s 转换成MySQL的日期函数
     *
     * @param s
     * @return
     */
    public String str2MySQLDate(String s) {
        return "str_to_date('" + s + "', '%Y-%m-%d')";
    }
}
